// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package ld

import (
	"cmd/link/internal/loader"
	"encoding/binary"
	"fmt"
	"os"
)

var atExitFuncs []func()

func AtExit(f func()) {
	atExitFuncs = append(atExitFuncs, f)
}

// runAtExitFuncs运行排队的AtExit函数集。
func runAtExitFuncs() {
	for i := len(atExitFuncs) - 1; i >= 0; i-- {
		atExitFuncs[i]()
	}
	atExitFuncs = nil
}

// 执行所有ATEXITFUNC后，Exit将带代码退出。
func Exit(code int) {
	runAtExitFuncs()
	os.Exit(code)
}

// Exitf记录一条错误消息，然后调用Exit（2）。
func Exitf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, os.Args[0]+": "+format+"\n", a...)
	nerrors++
	Exit(2)
}

// afterErrorAction在出现错误时更新“nerror”，并调用退出或
// 在适当的情况下恐慌。
func afterErrorAction() {
	nerrors++
	if *flagH {
		panic("error")
	}
	if nerrors > 20 {
		Exitf("too many errors")
	}
}

// Errorf记录一条错误消息。
// None
// 如果打印的错误超过20个，请退出并显示错误。
// None
// 记录错误意味着退出cmd/link时将删除任何
// 输出文件并返回非零错误代码。
// None
// TODO:删除。改用ctxt.Errorf。
// 所有剩余的调用都使用nil作为第一个参数。
func Errorf(dummy *int, format string, args ...interface{}) {
	format += "\n"
	fmt.Fprintf(os.Stderr, format, args...)
	afterErrorAction()
}

// Errorf方法记录一条错误消息。
// None
// 如果打印的错误超过20个，请退出并显示错误。
// None
// 记录错误意味着退出cmd/link时将删除任何
// 输出文件并返回非零错误代码。
func (ctxt *Link) Errorf(s loader.Sym, format string, args ...interface{}) {
	if ctxt.loader != nil {
		ctxt.loader.Errorf(s, format, args...)
		return
	}
	// 注意：这种情况预计不会经常发生。
	format = fmt.Sprintf("sym %d: %s", s, format)
	format += "\n"
	fmt.Fprintf(os.Stderr, format, args...)
	afterErrorAction()
}

func artrim(x []byte) string {
	i := 0
	j := len(x)
	for i < len(x) && x[i] == ' ' {
		i++
	}
	for j > i && x[j-1] == ' ' {
		j--
	}
	return string(x[i:j])
}

func stringtouint32(x []uint32, s string) {
	for i := 0; len(s) > 0; i++ {
		var buf [4]byte
		s = s[copy(buf[:], s):]
		x[i] = binary.LittleEndian.Uint32(buf[:])
	}
}

// 包含报告v是否在s中。
func contains(s []string, v string) bool {
	for _, x := range s {
		if x == v {
			return true
		}
	}
	return false
}
